package com.zz.apk.utils;

import android.content.ActivityNotFoundException;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.media.MediaMetadataRetriever;
import android.media.MediaScannerConnection;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.provider.MediaStore;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.Toast;

import com.zz.apk.service.DownloadService;
import com.zz.apk.utils.FileType;
import com.zz.apk.utils.MD5;
import com.zz.framework.core.ext.LogExtKt;
import com.zz.framework.core.ext.ToastExtKt;
import com.zz.framework.core.utils.LogUtils;
import com.zz.framework.R;
import com.zz.framework.core.BaseApp;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.nio.channels.FileChannel;
import java.nio.file.Files;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.DecimalFormat;
import java.util.Calendar;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

import androidx.annotation.RequiresApi;
import androidx.core.content.FileProvider;

public class FilesUtil {
    public static final String FILE_SAVE_DIR = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "dms" + File.separator;
    public static final String FILE_SAVE_PHOTO_TEMP_DIR = FILE_SAVE_DIR + "photoTemp" + File.separator;
    public static final String FILE_SAVE_TEMP_DIR = FILE_SAVE_DIR + "Temp" + File.separator;
    public static final String FILE_SAVE_LOG_DIR = FILE_SAVE_DIR + "Log" + File.separator;
    public static final String FILE_SAVE_CONFIG_DIR = FILE_SAVE_DIR + "Config" + File.separator;
    public static final String FILE_SAVE_DOWNLOAD_DIR = FILE_SAVE_DIR + "Download" + File.separator;
    public static final String FILE_TYPE_APK = ".apk";


    /**
     * @param myContext
     * @param assetsFileName 要复制的文件名
     * @param savePath       要保存的路径
     * @param saveName       复制后的文件名
     *                       testCopy(Context context)是一个测试例子。
     */


    public static String copyAssertFileTo(Context myContext, String assetsFileName, String savePath, String saveName) {
        String filename = savePath + File.separator + saveName;
        File dir = new File(savePath);
        // 如果目录不中存在，创建这个目录
        if (!dir.exists()) {
            dir.mkdirs();
        }
        try {
            //            if ((new File(filename)).exists() && BuildConfig.DEBUG) {
            //                (new File(filename)).delete();
            //            }
            if (!(new File(filename)).exists()) {
                InputStream is = myContext.getResources().getAssets().open(assetsFileName);
                FileOutputStream fos = new FileOutputStream(filename);
                byte[] buffer = new byte[7168];
                int count = 0;
                while ((count = is.read(buffer)) > 0) {
                    fos.write(buffer, 0, count);
                }
                fos.close();
                is.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            return filename;
        }
    }


    public static String getFileName(String path) {
        String result = "";
        if (!TextUtils.isEmpty(path)) {
            File file = new File(path);
            result = file.getName();
        }
        return result;
    }

    public static String getFileName(String path, String type) {
        String result = "";
        if (!TextUtils.isEmpty(path)) {
            File file = new File(path);
            result = file.getName();
        }
        if (TextUtils.isEmpty(result)) {
            result = "" + System.currentTimeMillis() + type;
        }
        return result;
    }

    public static String getUrlFileName(String url) {
        String result = "";
        if (!TextUtils.isEmpty(url)) {
            if (url.contains("/")) {
                result = url.substring(url.lastIndexOf("/") + 1);
            }
        }
        return result;
    }


    public static String getFileContent(String path) {
        String result = "";
        File file = new File(path);
        if (file.exists()) {
            try {
                FileInputStream f = new FileInputStream(file);
                BufferedReader bis = new BufferedReader(new InputStreamReader(f));
                String line = "";
                while ((line = bis.readLine()) != null) {
                    result += line;
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return result;

    }

    public static String getCacheFilePath(String dir, String url) {
        String cacheDir = dir + File.separator + getMD5Name(url);
        return cacheDir;
    }

    private static String getMD5Name(String url) {
        return MD5.toMD5(url);
    }

    public static String getUrlEnd(String url) {
        return url.substring(url.lastIndexOf("."));
    }

    public static String getUrlEnd(String url, String def) {
        if (TextUtils.isEmpty(url)) {
            if (url.contains("/")) {
                String[] arrays = url.split("/");
                if (arrays.length > 1) {
                    if (arrays[arrays.length - 1].contains(".")) {
                        return url.substring(url.lastIndexOf("."));
                    }
                }
            }
        }
        return def;
    }

    public static String formatFileSize(long b) {
        return formatFileSizeD((double) b);
    }

    public static String formatFileSizeD(double b) {
        if (b < 1024) {
            DecimalFormat fmt = new DecimalFormat("0.00B");
            return fmt.format(b);
        } else if (b < Math.pow(1024, 2)) {
            DecimalFormat fmt = new DecimalFormat("0.00KB");
            return fmt.format(b / 1024.0);
        } else if (b < Math.pow(1024, 3)) {
            DecimalFormat fmt = new DecimalFormat("0.00MB");
            return fmt.format(b / Math.pow(1024, 2));
        } else if (b < Math.pow(1024, 4)) {
            DecimalFormat fmt = new DecimalFormat("0.00GB");
            return fmt.format(b / Math.pow(1024, 3));
        } else if (b < Math.pow(1024, 5)) {
            DecimalFormat fmt = new DecimalFormat("0.00TB");
            return fmt.format(b / Math.pow(1024, 4));
        } else if (b < Math.pow(1024, 6)) {
            DecimalFormat fmt = new DecimalFormat("0.00PB");
            return fmt.format(b / Math.pow(1024, 5));
        } else if (b < Math.pow(1024, 7)) {
            DecimalFormat fmt = new DecimalFormat("0.00EB");
            return fmt.format(b / Math.pow(1024, 6));
        } else if (b < Math.pow(1024, 8)) {
            DecimalFormat fmt = new DecimalFormat("0.00ZB");
            return fmt.format(b / Math.pow(1024, 7));
        } else if (b < Math.pow(1024, 9)) {
            DecimalFormat fmt = new DecimalFormat("0.00YB");
            return fmt.format(b / Math.pow(1024, 8));
        } else if (b < Math.pow(1024, 10)) {
            DecimalFormat fmt = new DecimalFormat("0.00BB");
            return fmt.format(b / Math.pow(1024, 9));
        } else if (b < Math.pow(1024, 11)) {
            DecimalFormat fmt = new DecimalFormat("0.00NB");
            return fmt.format(b / Math.pow(1024, 10));
        } else if (b < Math.pow(1024, 12)) {
            DecimalFormat fmt = new DecimalFormat("0.00DB");
            return fmt.format(b / Math.pow(1024, 11));
        } else {
            DecimalFormat fmt = new DecimalFormat("0.00CB");
            return fmt.format(b / Math.pow(1024, 12));
        }
    }


    public static void downloadApk(Context context, String url) {
        Intent intent = new Intent(context, DownloadService.class);
        intent.putExtra(DownloadService.DOWNLOAD_URL, url);
        intent.putExtra(DownloadService.DOWNLOAD_TAG, DownloadService.TAG_APK);
        intent.putExtra(DownloadService.DOWNLOAD_CACHE_DIR, FILE_SAVE_DOWNLOAD_DIR);
        intent.putExtra(DownloadService.DOWNLOAD_FILE_TYPE, FILE_TYPE_APK);
        context.startService(intent);
    }

    public static void downloadFile(Context context, String url, String fileType) {
        Intent intent = new Intent(context, DownloadService.class);
        intent.putExtra(DownloadService.DOWNLOAD_URL, url);
        intent.putExtra(DownloadService.DOWNLOAD_TAG, DownloadService.TAG_FILE);
        intent.putExtra(DownloadService.DOWNLOAD_CACHE_DIR, FILE_SAVE_DOWNLOAD_DIR);
        intent.putExtra(DownloadService.DOWNLOAD_FILE_TYPE, fileType);
        context.startService(intent);
    }

    public static void install(Context mContext, String filePath) {
        File file = new File(filePath);
        if (!file.exists() || file.length() <= 0) {
            ToastExtKt.showToast(mContext, mContext.getString(R.string.toast_not_found_install_file));
            return;
        }
        File apkFile = new File(filePath);
        LogExtKt.loge(mContext, "开始执行安装: " + filePath);

        Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            LogExtKt.loge(mContext, "版本大于 N ，开始使用 fileProvider 进行安装");
            intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

            Uri contentUri = FileProvider.getUriForFile(mContext, mContext.getPackageName() + ".fileProvider", apkFile);
            //添加这一句表示对目标应用临时授权该Uri所代表的文件
            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            intent.setDataAndType(contentUri, "application/vnd.android.package-archive");
        } else {
            LogExtKt.loge(mContext, "正常进行安装");
            intent.setDataAndType(Uri.fromFile(apkFile), "application/vnd.android.package-archive");
        }
        mContext.startActivity(intent);
    }


    /**
     * 使用文件通道的方式复制文件
     *
     * @param s 源文件
     * @param t 复制到的新文件
     */

    public static boolean fileChannelCopy(File s, File t) {
        FileInputStream fi = null;
        FileOutputStream fo = null;
        FileChannel in = null;
        FileChannel out = null;
        try {

            fi = new FileInputStream(s);
            File dir = t.getParentFile();
            if (dir.exists() == false) {
                dir.mkdirs();
            }
            if (t.exists()) {
                t.delete();
            }
            t.createNewFile();
            fo = new FileOutputStream(t);

            in = fi.getChannel();//得到对应的文件通道

            out = fo.getChannel();//得到对应的文件通道

            in.transferTo(0, in.size(), out);//连接两个通道，并且从in通道读取，然后写入out通道

        } catch (IOException e) {

            e.printStackTrace();
            return false;
        } finally {

            try {

                fi.close();

                in.close();

                fo.close();

                out.close();
                return true;
            } catch (Exception e) {

                e.printStackTrace();
                return false;
            }

        }

    }

    public static void fileScan(Context context, String filePath) {
        Uri data = Uri.parse("file://" + filePath);
        context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, data));
    }

    public static boolean isGif(String path) {
        String type = FileType.getFileHeader(path);
        if (type != null && FileType.GIF_BYTE.contains(type)) {
            return true;
        }
        return false;
    }


    public static boolean copyChannelFile(String source, String dist) {
        if (!TextUtils.isEmpty(source) && !TextUtils.isEmpty(dist) && FilesUtil.fileChannelCopy(new File(source), new File(dist))) {
            return true;
        }
        return false;
    }


    /**
     * 调用第三方浏览器打开
     *
     * @param context
     * @param url     要浏览的资源地址
     */
    public static void openBrowser(Context context, String url) {
        final Intent intent = new Intent();
        intent.setAction(Intent.ACTION_VIEW);
        intent.setData(Uri.parse(url));
        // 注意此处的判断intent.resolveActivity()可以返回显示该Intent的Activity对应的组件名
        // 官方解释 : Name of the component implementing an activity that can display the intent
        if (intent.resolveActivity(context.getPackageManager()) != null) {
            final ComponentName componentName = intent.resolveActivity(context.getPackageManager()); // 打印Log   ComponentName到底是什么 L.d("componentName = " + componentName.getClassName());
            context.startActivity(Intent.createChooser(intent, "请选择浏览器"));
        } else {
            Toast.makeText(context.getApplicationContext(), "请下载浏览器", Toast.LENGTH_SHORT).show();
        }
    }

    public static Uri getUri(Context context, File file) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            return FileProvider.getUriForFile(context, context.getPackageName() + ".fileProvider", file);
        } else {
            return Uri.fromFile(file);
        }
    }

    ///storage/emulated/0/dms/Download/12928f2e77924e35b5c0ff1851c4652a.xlsx
    public static void openFile(Context context, File file) {
        try {
            if (file == null) {
                return;
            }
            Intent intent = new Intent();
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            //设置intent的Action属性
            intent.setAction(Intent.ACTION_VIEW);
            //获取文件file的MIME类型
            String type = getMIMEType(file);
            //设置intent的data和Type属性。
            intent.setDataAndType(getUri(context, file), type);
            //跳转
            context.startActivity(intent);
        } catch (ActivityNotFoundException e) {
            Toast.makeText(context, "sorry附件不能打开，请下载相关软件！", Toast.LENGTH_LONG).show();
        }
    }

    private static String getMIMEType(File file) {
        String type = "text/html";
        String fName = file.getName();
        //获取后缀名前的分隔符"."在fName中的位置。   
        int dotIndex = fName.lastIndexOf(".");
        if (dotIndex < 0) {
            return type;
        }
        /* 获取文件的后缀名*/
        String end = fName.substring(dotIndex, fName.length()).toLowerCase();
        if (end == "") {
            return type;
        }
        //在MIME和文件类型的匹配表中找到对应的MIME类型。   
        for (int i = 0; i < MIME_MapTable.length; i++) {
            if (end.equals(MIME_MapTable[i][0])) {
                type = MIME_MapTable[i][1];
            }
        }
        return type;
    }

    private static String[][] MIME_MapTable = {
            //{后缀名，MIME类型}   
            {".3gp", "video/3gpp"}, {".apk", "application/vnd.android.package-archive"}, {".asf", "video/x-ms-asf"}, {".avi", "video/x-msvideo"}, {".bin", "application/octet-stream"}, {".bmp", "image/bmp"}, {".c", "text/plain"}, {".class", "application/octet-stream"}, {".conf", "text/plain"}, {".cpp", "text/plain"}, {".doc", "application/msword"}, {".docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document"}, {".xls", "application/vnd.ms-excel"}, {".xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"}, {".exe", "application/octet-stream"}, {".gif", "image/gif"}, {".gtar", "application/x-gtar"}, {".gz", "application/x-gzip"}, {".h", "text/plain"}, {".htm", "text/html"}, {".html", "text/html"}, {".jar", "application/java-archive"}, {".java", "text/plain"}, {".jpeg", "image/jpeg"}, {".jpg", "image/jpeg"}, {".js", "application/x-javascript"}, {".log", "text/plain"}, {".m3u", "audio/x-mpegurl"}, {".m4a", "audio/mp4a-latm"}, {".m4b", "audio/mp4a-latm"}, {".m4p", "audio/mp4a-latm"}, {".m4u", "video/vnd.mpegurl"}, {".m4v", "video/x-m4v"}, {".mov", "video/quicktime"}, {".mp2", "audio/x-mpeg"}, {".mp3", "audio/x-mpeg"}, {".mp4", "video/mp4"}, {".mpc", "application/vnd.mpohun.certificate"}, {".mpe", "video/mpeg"}, {".mpeg", "video/mpeg"}, {".mpg", "video/mpeg"}, {".mpg4", "video/mp4"}, {".mpga", "audio/mpeg"}, {".msg", "application/vnd.ms-outlook"}, {".ogg", "audio/ogg"}, {".pdf", "application/pdf"}, {".png", "image/png"}, {".pps", "application/vnd.ms-powerpoint"}, {".ppt", "application/vnd.ms-powerpoint"}, {".pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation"}, {".prop", "text/plain"}, {".rc", "text/plain"}, {".rmvb", "audio/x-pn-realaudio"}, {".rtf", "application/rtf"}, {".sh", "text/plain"}, {".tar", "application/x-tar"}, {".tgz", "application/x-compressed"}, {".txt", "text/plain"}, {".wav", "audio/x-wav"}, {".wma", "audio/x-ms-wma"}, {".wmv", "audio/x-ms-wmv"}, {".wps", "application/vnd.ms-works"}, {".xml", "text/plain"}, {".z", "application/x-compress"}, {".zip", "application/x-zip-compressed"}, {"", "*/*"}};


    public static String[] getFileTypeArray() {
        String[] stringArray = new String[]{"doc", "docx", "xls", "xlsx", "pdf", "pptx", "txt", "jpeg", "jpg", "gif", "bmp", "png", "mp4", "m4u", "m4v", "mov", ".3gp", "asf", "avi", "mpe", "mpeg", "mpg", "mpg4", "mpga", "rmvb", "ogg", "wav", "wma", "wmv", "m3u", "m4a", "m4b", "m4p", "mp2", "mp3", "bin", "class", "conf", "cpp", "c", "exe", "gtar", "gz", "h", "htm", "html", "jar", "java", "js", "log", "mpc", "msg", "pps", "ppt", "prop", "rc", "rtf", "sh", "tar", "tgz", "wps", "xml", "z", "zip", "apk", "exe", "ipa", "app", "hap"};
        return stringArray;
    }


    public static int getFileType(String fileName) {
        // // 1.文档 2.图片  3.视频  4.音乐   5.其他 6应用
        Map<String, Integer> type = new HashMap<>();
        //{后缀名，MIME类型}

        type.put("txt", 1);

        type.put("jpeg", 2);
        type.put("jpg", 2);
        type.put("gif", 2);
        type.put("bmp", 2);
        type.put("png", 2);
        type.put("avif", 2);
        type.put("heic", 2);//动态图片

        type.put("mp4", 3);
        type.put("mkv", 3);
        type.put("m4u", 3);
        type.put("m4v", 3);
        type.put("mov", 3);
        type.put(".3gp", 3);
        type.put("asf", 3);
        type.put("avi", 3);
        type.put("wmv", 3);
        type.put("flv", 3);
        type.put("mpe", 3);
        type.put("mpeg", 3);
        type.put("mpg", 3);
        type.put("mpg4", 3);
        type.put("mpeg4", 3);
        type.put("mpga", 3);
        type.put("rmvb", 3);
        type.put("rm", 3);

        type.put("aac", 4);
        type.put("ogg", 4);
        type.put("wav", 4);
        type.put("wma", 4);
        type.put("m3u", 4);
        type.put("m4a", 4);
        type.put("m4b", 4);
        type.put("m4p", 4);
        type.put("m4r", 4);
        type.put("mp2", 4);
        type.put("mp3", 4);


        type.put("bin", 5);
        type.put("class", 5);
        type.put("conf", 5);
        type.put("cpp", 5);
        type.put("c", 5);
        type.put("exe", 5);
        type.put("gtar", 5);
        type.put("gz", 5);
        type.put("h", 5);
        type.put("htm", 5);
        type.put("html", 5);
        type.put("jar", 5);
        type.put("java", 5);
        type.put("js", 5);
        type.put("log", 5);
        type.put("mpc", 5);
        type.put("msg", 5);
        type.put("pps", 5);
        type.put("prop", 5);
        type.put("rc", 5);
        type.put("rtf", 5);
        type.put("sh", 5);
        type.put("tar", 5);
        type.put("tgz", 5);
        type.put("wps", 5);
        type.put("xml", 5);
        type.put("z", 5);
        type.put("zip", 5);


        type.put("apk", 5);
        type.put("exe", 5);
        type.put("ipa", 5);
        type.put("app", 5);
        type.put("hap", 5);

        type.put("docx", 6);
        type.put("doc", 6);

        type.put("xls", 7);
        type.put("xlsx", 7);

        type.put("ppt", 8);
        type.put("pptx", 8);

        type.put("pdf", 9);
        type.put("epub", 11);


        String fileExtensionName = getFileExtensionName(fileName);
        if (type.containsKey(fileExtensionName)) {
            return type.get(fileExtensionName);
        } else {
            return 5;
        }
    }

    /**
     * 获取文件后缀名
     *
     * @return 获取不到文件名后缀，返回null
     */
    public static String getFileExtensionName(String fileName) {
        if (TextUtils.isEmpty(fileName)) {
            return null;
        }
        int endP = fileName.lastIndexOf(".");
        return endP > -1 ? fileName.substring(endP + 1).toLowerCase() : null;
    }

    //将文件转换成Byte数组
    public static byte[] getBytesByFile(String pathStr) {
        File file = new File(pathStr);
        try {
            FileInputStream fis = new FileInputStream(file);
            ByteArrayOutputStream bos = new ByteArrayOutputStream(1000);
            byte[] b = new byte[1000];
            int n;
            while ((n = fis.read(b)) != -1) {
                bos.write(b, 0, n);
            }
            fis.close();
            byte[] data = bos.toByteArray();
            bos.close();
            return data;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    //将Byte数组转换成文件
    public static void getFileByBytes(byte[] bytes, String filePath, String fileName) {
        BufferedOutputStream bos = null;
        FileOutputStream fos = null;
        File file = null;
        try {
            File dir = new File(filePath);
            if (!dir.exists()) {// 判断文件目录是否存在
                dir.mkdirs();
            }
            file = new File(filePath + fileName);
            fos = new FileOutputStream(file);
            bos = new BufferedOutputStream(fos);
            bos.write(bytes);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (bos != null) {
                try {
                    bos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }


    public static Bitmap viewToBitmap(View view) {
        view.setDrawingCacheEnabled(true);
        view.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH);
        view.setDrawingCacheBackgroundColor(Color.WHITE);
        // 把一个View转换成图片
        Bitmap cachebmp = loadBitmapFromView(view);
        view.destroyDrawingCache();
        return cachebmp;
    }

    /**
     * 将view转存到相册
     * @param view
     * @return
     */
    public static boolean viewSaveToImage(View view) {
        // 把一个View转换成图片
        Bitmap cachebmp = viewToBitmap(view);
        boolean isSucess = saveBitmapToAlbum(view.getContext(), cachebmp);
        if (isSucess) {
            ToastExtKt.showToast("保存成功");
        }
        return isSucess;
    }

    public static Bitmap loadBitmapFromView(View v) {
        try {
            int w = v.getWidth();
            int h = v.getHeight();
            Bitmap bmp = Bitmap.createBitmap(w, h, Bitmap.Config.RGB_565);
            v.layout(v.getLeft(), v.getTop(), v.getRight(), v.getBottom());
            Canvas c = new Canvas(bmp);
            // Draw background
            Drawable bgDrawable = v.getBackground();
            if (bgDrawable != null) {
                bgDrawable.draw(c);
            } else {
                c.drawColor(Color.WHITE);
            }
            v.draw(c);
            return bmp;
        } catch (Exception e) {
            return null;
        }
    }


    /**
     * 将bitmap保存到系统相册
     */
    public static boolean saveBitmapToAlbum(Context context, Bitmap bitmap) {
        if (bitmap == null) {
            return false;
        }
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
            return saveBitmapToAlbumBeforeQ(context, bitmap);
        } else {
            return saveBitmapToAlbumAfterQ(context, bitmap);
        }
    }

    @RequiresApi(api = Build.VERSION_CODES.Q)
    private static boolean saveBitmapToAlbumAfterQ(Context context, Bitmap bitmap) {
        Uri contentUri;
        if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
            contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
        } else {
            contentUri = MediaStore.Images.Media.INTERNAL_CONTENT_URI;
        }
        ContentValues contentValues = getImageContentValues(context);
        Uri uri = context.getContentResolver().insert(contentUri, contentValues);
        if (uri == null) {
            return false;
        }
        OutputStream os = null;
        try {
            os = context.getContentResolver().openOutputStream(uri);
            bitmap.compress(Bitmap.CompressFormat.JPEG, 50, os);
            //if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            //    Files.copy(bitmapFile.toPath(), os);
            //}
            contentValues.clear();
            contentValues.put(MediaStore.MediaColumns.IS_PENDING, 0);
            context.getContentResolver().update(uri, contentValues, null, null);
            return true;
        } catch (Exception e) {
            context.getContentResolver().delete(uri, null, null);
            e.printStackTrace();
            return false;
        } finally {
            try {
                if (os != null) {
                    os.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private static boolean saveBitmapToAlbumBeforeQ(Context context, Bitmap bitmap) {
        File picDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM);
        File destFile = new File(picDir, context.getPackageName() + File.separator + System.currentTimeMillis() + ".jpg");
        //            FileUtils.copy(imageFile, destFile.getAbsolutePath());
        OutputStream os = null;
        boolean result = false;
        try {
            if (!destFile.exists()) {
                destFile.getParentFile().mkdirs();
                destFile.createNewFile();
            }
            os = new BufferedOutputStream(new FileOutputStream(destFile));
            result = bitmap.compress(Bitmap.CompressFormat.JPEG, 50, os);
            if (!bitmap.isRecycled()) {
                bitmap.recycle();
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (os != null) {
                    os.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        MediaScannerConnection.scanFile(context, new String[]{destFile.getAbsolutePath()}, new String[]{"image/*"}, (path, uri) -> {
            Log.d(TAG, "saveImgToAlbum: " + path + " " + uri);
            // Scan Completed
        });
        return result;
    }

    /**
     * 获取图片的ContentValue
     *
     * @param context
     */
    @RequiresApi(api = Build.VERSION_CODES.Q)
    public static ContentValues getImageContentValues(Context context) {
        ContentValues contentValues = new ContentValues();
        //设置文件名称
        contentValues.put(MediaStore.Images.Media.DISPLAY_NAME, System.currentTimeMillis() + ".jpg");
        contentValues.put(MediaStore.Images.Media.MIME_TYPE, "image/*");
        contentValues.put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_DCIM + File.separator + context.getPackageName());
        contentValues.put(MediaStore.MediaColumns.IS_PENDING, 1);
        contentValues.put(MediaStore.Images.Media.DATE_TAKEN, System.currentTimeMillis());
        contentValues.put(MediaStore.Images.Media.DATE_MODIFIED, System.currentTimeMillis());
        contentValues.put(MediaStore.Images.Media.DATE_ADDED, System.currentTimeMillis());
        return contentValues;
    }

    /**
     * 将视频保存到系统相册
     */
    public static boolean saveVideoToAlbum(Context context, String videoFile) {
        Log.d(TAG, "saveVideoToAlbum() videoFile = [" + videoFile + "]");
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
            return saveVideoToAlbumBeforeQ(context, videoFile);
        } else {
            return saveVideoToAlbumAfterQ(context, videoFile);
        }


    }

    private static boolean saveVideoToAlbumAfterQ(Context context, String videoFile) {
        try {
            ContentResolver contentResolver = context.getContentResolver();
            File tempFile = new File(videoFile);
            ContentValues contentValues = getVideoContentValues(context, tempFile, System.currentTimeMillis());
            Uri uri = contentResolver.insert(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, contentValues);
            copyFileAfterQ(context, contentResolver, tempFile, uri);
            contentValues.clear();
            contentValues.put(MediaStore.MediaColumns.IS_PENDING, 0);
            context.getContentResolver().update(uri, contentValues, null, null);
            context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, uri));
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    private static boolean saveVideoToAlbumBeforeQ(Context context, String videoFile) {
        File picDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM);
        File tempFile = new File(videoFile);
        File destFile = new File(picDir, context.getPackageName() + File.separator + tempFile.getName());
        FileInputStream ins = null;
        BufferedOutputStream ous = null;
        try {
            ins = new FileInputStream(tempFile);
            ous = new BufferedOutputStream(new FileOutputStream(destFile));
            long nread = 0L;
            byte[] buf = new byte[1024];
            int n;
            while ((n = ins.read(buf)) > 0) {
                ous.write(buf, 0, n);
                nread += n;
            }
            MediaScannerConnection.scanFile(context, new String[]{destFile.getAbsolutePath()}, new String[]{"video/*"}, (path, uri) -> {
                Log.d(TAG, "saveVideoToAlbum: " + path + " " + uri);
                // Scan Completed
            });
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        } finally {
            try {
                if (ins != null) {
                    ins.close();
                }
                if (ous != null) {
                    ous.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private static void copyFileAfterQ(Context context, ContentResolver localContentResolver, File tempFile, Uri localUri) throws IOException {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && context.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.Q) {
            //拷贝文件到相册的uri,android10及以上得这么干，否则不会显示。可以参考ScreenMediaRecorder的save方法
            OutputStream os = localContentResolver.openOutputStream(localUri);
            Files.copy(tempFile.toPath(), os);
            os.close();
            tempFile.delete();
        }
    }


    /**
     * 获取视频的contentValue
     */
    public static ContentValues getVideoContentValues(Context context, File paramFile, long timestamp) {
        ContentValues localContentValues = new ContentValues();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            localContentValues.put(MediaStore.Video.Media.RELATIVE_PATH, Environment.DIRECTORY_DCIM + File.separator + context.getPackageName());
        }
        localContentValues.put(MediaStore.Video.Media.TITLE, paramFile.getName());
        localContentValues.put(MediaStore.Video.Media.DISPLAY_NAME, paramFile.getName());
        localContentValues.put(MediaStore.Video.Media.MIME_TYPE, "video/mp4");
        localContentValues.put(MediaStore.Video.Media.DATE_TAKEN, timestamp);
        localContentValues.put(MediaStore.Video.Media.DATE_MODIFIED, timestamp);
        localContentValues.put(MediaStore.Video.Media.DATE_ADDED, timestamp);
        localContentValues.put(MediaStore.Video.Media.SIZE, paramFile.length());
        return localContentValues;
    }


    /**
     * 返回视频播放总时长
     *
     * @param vedioFile
     * @return
     */
    public static Long getVedioTotalTime(File vedioFile) {
        if (!vedioFile.exists()) {
            LogUtils.error("视频文件不存在");
            return null;
        }
        MediaMetadataRetriever retriever = new MediaMetadataRetriever();
        retriever.setDataSource(vedioFile.getAbsolutePath());
        String timeString = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
        Long time = Long.valueOf(timeString);
        return time;
    }

    /**
     * 获取视频缩略图
     *
     * @param vedioFile
     * @return
     */
    public static Bitmap getVedioThumbnail(File vedioFile) {
        if (!vedioFile.exists()) {
            LogUtils.error("视频文件不存在");
            return null;
        }
        MediaMetadataRetriever retriever = new MediaMetadataRetriever();
        retriever.setDataSource(vedioFile.getAbsolutePath());
        Bitmap bitmap = retriever.getFrameAtTime();
        return bitmap;
    }

    /**
     * 获取视频在某个时间点的缩略图
     *
     * @param vedioFile
     * @return
     */
    public static Bitmap getVedioThumbnail(File vedioFile, long time) {
        if (!vedioFile.exists()) {
            LogUtils.error("视频文件不存在");
            return null;
        }
        MediaMetadataRetriever retriever = new MediaMetadataRetriever();
        retriever.setDataSource(vedioFile.getAbsolutePath());
        Bitmap bitmap = retriever.getFrameAtTime(time);//参数为毫秒,就是返回靠近这个时间的帧图
        return bitmap;
    }

    public static void getPlayTime(String path) {
        MediaMetadataRetriever mmr = new MediaMetadataRetriever();
        try {
            if (path != null) {
                FileInputStream inputStream = new FileInputStream(new File(path).getAbsolutePath());
                mmr.setDataSource(inputStream.getFD());
                //HashMap<String, String> headers = null;
                //if (headers == null) {
                //    headers = new HashMap<String, String>();
                //    headers.put("User-Agent", "Mozilla/5.0 (Linux; U; Android 4.4.2; zh-CN; MW-KW-001 Build/JRO03C) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 UCBrowser/1.0.0.001 U4/0.8.0 Mobile Safari/533.1");
                //}
                //mmr.setDataSource(mUri, headers);
            }
            String duration = mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);//时长(毫秒)
            String width = mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH);//宽
            String height = mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT);//高
            LogUtils.error("playtime:" + duration + "w=" + width + "h=" + height);
        } catch (Exception ex) {
            Log.e("TAG", "MediaMetadataRetriever exception " + ex);
        } finally {
            try {
                mmr.release();
            } catch (IOException mE) {
               mE.printStackTrace();
            }
        }
    }


    /**
     * 格式化单位
     *
     * @param size
     * @return
     */


    public static String getFormatSize(double size) {
        double kiloByte = size / 1024;
        if (kiloByte < 1) {
            return size + "B";
        }
        double megaByte = kiloByte / 1024;
        if (megaByte < 1) {
            BigDecimal result1 = new BigDecimal(Double.toString(kiloByte));
            return result1.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString() + "KB";
        }
        double gigaByte = megaByte / 1024;
        if (gigaByte < 1) {
            BigDecimal result2 = new BigDecimal(Double.toString(megaByte));
            return result2.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString() + "MB";
        }

        double teraBytes = gigaByte / 1024;
        if (teraBytes < 1) {
            BigDecimal result3 = new BigDecimal(Double.toString(gigaByte));
            return result3.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString() + "GB";
        }
        BigDecimal result4 = new BigDecimal(teraBytes);
        return result4.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString() + "TB";
    }


    public static void updatePhotoMedia(File file, Context context) {
        Intent intent = new Intent();
        intent.setAction(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
        intent.setData(Uri.fromFile(file));
        context.sendBroadcast(intent);

        MediaScannerConnection.scanFile(context, new String[]{file.toString()}, new String[]{file.getName()}, null);
    }

    //保存到数据库
    public static void savePhotoToMedia(Context context, File imgfile) {
        String uriString = null;
        try {
            uriString = MediaStore.Images.Media.insertImage(context.getContentResolver(), imgfile.getPath(), imgfile.getName(), null);
            File file = new File(getRealPathFromURI(Uri.parse(uriString), context));
            updatePhotoMedia(file, context);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }

    public static void savePhotoToMedia(Context context, Bitmap bitmap) {
        String uriString = MediaStore.Images.Media.insertImage(context.getContentResolver(), bitmap, null, null);
        File file = new File(getRealPathFromURI(Uri.parse(uriString), context));
        updatePhotoMedia(file, context);
    }

    //得到绝对地址
    private static String getRealPathFromURI(Uri contentUri, Context context) {
        String[] proj = {MediaStore.Images.Media.DATA};
        Cursor cursor = context.getContentResolver().query(contentUri, proj, null, null, null);
        int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
        cursor.moveToFirst();
        String fileStr = cursor.getString(column_index);
        cursor.close();
        return fileStr;
    }


    /**
     * 得到手机的缓存目录
     *
     * @param context
     * @return
     */
    public static File getCacheDir(Context context) {
        if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
            File cacheDir = context.getExternalCacheDir();
            if (cacheDir != null && (cacheDir.exists() || cacheDir.mkdirs())) {
                return cacheDir;
            }
        }
        File cacheDir = context.getCacheDir();
        return cacheDir;
    }

    public static File getCacheDir(Context context, String type) {
        File skinDir = new File(getCacheDir(context), type);
        if (skinDir.exists()) {
            skinDir.mkdirs();
        }
        return skinDir;
    }

    /**
     * 得到皮肤目录
     *
     * @param context
     * @return
     */
    public static File getSkinDir(Context context) {
        File skinDir = new File(getCacheDir(context), "skin");
        if (skinDir.exists()) {
            skinDir.mkdirs();
        }
        return skinDir;
    }

    public static String getSkinDirPath(Context context) {
        return getSkinDir(context).getAbsolutePath();
    }


    private static String FILE_WRITING_ENCODING = "UTF-8";
    private static String FILE_READING_ENCODING = "UTF-8";

    public static String readFile(String _sFileName, String _sEncoding) throws Exception {
        StringBuffer buffContent = null;
        String sLine;

        FileInputStream fis = null;
        BufferedReader buffReader = null;
        if (_sEncoding == null || "".equals(_sEncoding)) {
            _sEncoding = FILE_READING_ENCODING;
        }

        try {
            fis = new FileInputStream(_sFileName);
            buffReader = new BufferedReader(new InputStreamReader(fis, _sEncoding));
            boolean zFirstLine = "UTF-8".equalsIgnoreCase(_sEncoding);
            while ((sLine = buffReader.readLine()) != null) {
                if (buffContent == null) {
                    buffContent = new StringBuffer();
                } else {
                    buffContent.append("\n");
                }
                if (zFirstLine) {
                    sLine = removeBomHeaderIfExists(sLine);
                    zFirstLine = false;
                }
                buffContent.append(sLine);
            }// end while
            return (buffContent == null ? "" : buffContent.toString());
        } catch (FileNotFoundException ex) {
            throw new Exception("要读取的文件没有找到!", ex);
        } catch (IOException ex) {
            throw new Exception("读取文件时错误!", ex);
        } finally {
            // 增加异常时资源的释放
            try {
                if (buffReader != null) {
                    buffReader.close();
                }
                if (fis != null) {
                    fis.close();
                }
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    }


    public static void moveRawToDir(Context context, String rawName, String dir) {
        try {
            writeFile(context.getAssets().open(rawName), dir, true);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static File writeFile(String path, String content, String encoding, boolean isOverride) throws Exception {
        if (TextUtils.isEmpty(encoding)) {
            encoding = FILE_WRITING_ENCODING;
        }
        InputStream is = new ByteArrayInputStream(content.getBytes(encoding));
        return writeFile(is, path, isOverride);
    }

    public static File writeFile(InputStream is, String path, boolean isOverride) throws Exception {
        String sPath = extractFilePath(path);
        if (!pathExists(sPath)) {
            makeDir(sPath, true);
        }

        if (!isOverride && fileExists(path)) {
            if (path.contains(".")) {
                String suffix = path.substring(path.lastIndexOf("."));
                String pre = path.substring(0, path.lastIndexOf("."));
                path = pre + "_" + System.currentTimeMillis() + suffix;
            } else {
                path = path + "_" + System.currentTimeMillis();
            }
        }

        FileOutputStream os = null;
        File file = null;

        try {
            file = new File(path);
            os = new FileOutputStream(file);
            int byteCount = 0;
            byte[] bytes = new byte[1024];

            while ((byteCount = is.read(bytes)) != -1) {
                os.write(bytes, 0, byteCount);
            }
            os.flush();

            return file;
        } catch (Exception e) {
            e.printStackTrace();
            throw new Exception("写文件错误", e);
        } finally {
            try {
                if (os != null) {
                    os.close();
                }
                if (is != null) {
                    is.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 移除字符串中的BOM前缀
     *
     * @param _sLine 需要处理的字符串
     * @return 移除BOM后的字符串.
     */
    private static String removeBomHeaderIfExists(String _sLine) {
        if (_sLine == null) {
            return null;
        }
        String line = _sLine;
        if (line.length() > 0) {
            char ch = line.charAt(0);
            // 使用while是因为用一些工具看到过某些文件前几个字节都是0xfffe.
            // 0xfeff,0xfffe是字节序的不同处理.JVM中,一般是0xfeff
            while ((ch == 0xfeff || ch == 0xfffe)) {
                line = line.substring(1);
                if (line.length() == 0) {
                    break;
                }
                ch = line.charAt(0);
            }
        }
        return line;
    }

    /**
     * 从文件的完整路径名（路径+文件名）中提取 路径（包括：Drive+Directroy )
     *
     * @param _sFilePathName
     * @return
     */
    public static String extractFilePath(String _sFilePathName) {
        int nPos = _sFilePathName.lastIndexOf('/');
        if (nPos < 0) {
            nPos = _sFilePathName.lastIndexOf('\\');
        }

        return (nPos >= 0 ? _sFilePathName.substring(0, nPos + 1) : "");
    }

    /**
     * 检查指定文件的路径是否存在
     *
     * @param _sPathFileName 文件名称(含路径）
     * @return 若存在，则返回true；否则，返回false
     */
    public static boolean pathExists(String _sPathFileName) {
        String sPath = extractFilePath(_sPathFileName);
        return fileExists(sPath);
    }

    public static boolean fileExists(String _sPathFileName) {
        File file = new File(_sPathFileName);
        return file.exists();
    }

    /**
     * 创建目录
     *
     * @param _sDir             目录名称
     * @param _bCreateParentDir 如果父目录不存在，是否创建父目录
     * @return
     */
    public static boolean makeDir(String _sDir, boolean _bCreateParentDir) {
        boolean zResult = false;
        File file = new File(_sDir);
        if (_bCreateParentDir) {
            zResult = file.mkdirs(); // 如果父目录不存在，则创建所有必需的父目录
        } else {
            zResult = file.mkdir(); // 如果父目录不存在，不做处理
        }
        if (!zResult) {
            zResult = file.exists();
        }
        return zResult;
    }


    private static final String TAG = "FilesUtil";

    /**
     * 校验文件MD5码
     */
    public static boolean checkMD5(String md5, File updateFile) {
        if (TextUtils.isEmpty(md5) || updateFile == null) {
            Log.e(TAG, "MD5 string empty or updateFile null");
            return false;
        }

        String calculatedDigest = getFileMD5(updateFile);
        if (calculatedDigest == null) {
            Log.e(TAG, "calculatedDigest null");
            return false;
        }
        return calculatedDigest.equalsIgnoreCase(md5);
    }

    /**
     * 获取文件MD5码
     */
    public static String getFileMD5(File updateFile) {
        MessageDigest digest;
        try {
            digest = MessageDigest.getInstance("MD5");
        } catch (NoSuchAlgorithmException e) {
            Log.e(TAG, "Exception while getting digest", e);
            return null;
        }

        InputStream is;
        try {
            is = new FileInputStream(updateFile);
        } catch (FileNotFoundException e) {
            Log.e(TAG, "Exception while getting FileInputStream", e);
            return null;
        }

        byte[] buffer = new byte[8192];
        int read;
        try {
            while ((read = is.read(buffer)) > 0) {
                digest.update(buffer, 0, read);
            }
            byte[] md5sum = digest.digest();
            BigInteger bigInt = new BigInteger(1, md5sum);
            String output = bigInt.toString(16);
            // Fill to 32 chars
            output = String.format("%32s", output).replace(' ', '0');
            return output;
        } catch (IOException e) {
            throw new RuntimeException("Unable to process file for MD5", e);
        } finally {
            try {
                is.close();
            } catch (IOException e) {
                Log.e(TAG, "Exception on closing MD5 input stream", e);
            }
        }
    }

    /**
     * 解压缩功能.
     * 将ZIP_FILENAME文件解压到ZIP_DIR目录下.
     *
     * @param zipFile    压缩文件
     * @param folderPath 解压目录
     */
    public static int unZipFile(File zipFile, String folderPath) {
        ZipFile zfile = null;
        try {
            zfile = new ZipFile(zipFile);
            Enumeration zList = zfile.entries();
            ZipEntry ze = null;
            byte[] buf = new byte[1024];
            while (zList.hasMoreElements()) {
                ze = (ZipEntry) zList.nextElement();
                if (ze.isDirectory()) {
                    //                    L.d(TAG, "ze.getName() = " + ze.getName());
                    String dirstr = folderPath + ze.getName();
                    //dirstr.trim();
                    dirstr = new String(dirstr.getBytes("8859_1"), "GB2312");
                    //                    L.d(TAG, "str = " + dirstr);
                    File f = new File(dirstr);
                    f.mkdir();
                    continue;
                }
                //                L.d(TAG, "ze.getName() = " + ze.getName());
                OutputStream os = new BufferedOutputStream(new FileOutputStream(getRealFileName(folderPath, ze.getName())));
                InputStream is = new BufferedInputStream(zfile.getInputStream(ze));
                int readLen = 0;
                while ((readLen = is.read(buf)) != -1) {
                    os.write(buf, 0, readLen);
                }
                is.close();
                os.close();
            }
            zfile.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return 0;
    }

    /**
     * 给定根目录，返回一个相对路径所对应的实际文件名.
     *
     * @param baseDir     指定根目录
     * @param absFileName 相对路径名，来自于ZipEntry中的name
     * @return java.io.File 实际的文件
     */
    private static File getRealFileName(String baseDir, String absFileName) {
        String[] dirs = absFileName.split("/");
        File ret = new File(baseDir);
        String substr = null;
        if (dirs.length > 1) {
            for (int i = 0; i < dirs.length - 1; i++) {
                substr = dirs[i];
                try {
                    //substr.trim();
                    substr = new String(substr.getBytes("8859_1"), "GB2312");
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }
                ret = new File(ret, substr);
            }
            //            L.d("upZipFile", "1ret = " + ret);
            if (!ret.exists()) {
                ret.mkdirs();
            }
            substr = dirs[dirs.length - 1];
            try {
                //substr.trim();
                substr = new String(substr.getBytes("8859_1"), "GB2312");
                //                L.d("upZipFile", "substr = " + substr);
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
            ret = new File(ret, substr);
            //            L.d("upZipFile", "2ret = " + ret);
            return ret;
        }

        return ret;
    }


    public static boolean openFile(File file) {
        try {
            if (!file.exists()) {
                return false;
            }
            Intent intent = new Intent();
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            //设置intent的Action属性
            intent.setAction(Intent.ACTION_VIEW);
            //获取文件file的MIME类型
            String type = getMIMEType(file);
            //设置intent的data和Type属性。android 7.0以上crash,改用provider
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                Uri fileUri = FileProvider.getUriForFile(BaseApp.Companion.getContext(), BaseApp.Companion.getContext().getPackageName() + ".fileProvider", file);//android 7.0以上
                intent.setDataAndType(fileUri, type);
                grantUriPermission(BaseApp.Companion.getContext(), fileUri, intent);
            } else {
                intent.setDataAndType(/*uri*/Uri.fromFile(file), type);
            }
            //跳转
            BaseApp.Companion.getContext().startActivity(intent);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    private static void grantUriPermission(Context context, Uri fileUri, Intent intent) {
        List<ResolveInfo> resInfoList = context.getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
        for (ResolveInfo resolveInfo : resInfoList) {
            String packageName = resolveInfo.activityInfo.packageName;
            context.grantUriPermission(packageName, fileUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
        }
    }


    public static String saveBitmapToCacheFile(Bitmap cachebmp) {
        FileOutputStream fos;
        String imagePath = "";
        try {
            // 判断手机设备是否有SD卡
            boolean isHasSDCard = Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);
            if (isHasSDCard) {
                // SD卡根目录
                File sdRoot = BaseApp.Companion.getContext().getCacheDir();
                File appDir = new File(sdRoot, "smallDragon");
                if (!appDir.exists()) {
                    appDir.mkdir();
                }
                File file = new File(appDir, Calendar.getInstance().getTimeInMillis() + ".png");
                fos = new FileOutputStream(file);
                imagePath = file.getAbsolutePath();
            } else {
                throw new Exception("创建文件失败!");
            }
            cachebmp.compress(Bitmap.CompressFormat.PNG, 90, fos);
            fos.flush();
            fos.close();
            //            ToastExtKt.showToast("保存成功");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (cachebmp != null) {
                cachebmp.recycle();
                cachebmp = null;
            }
        }
        LogUtils.error("imagePath=" + imagePath);
        return imagePath;
    }

}
